<template>
  <div class="search-suggestion">
    <van-cell
      v-for="(item, index) in suggestion"
      :key="index"
      icon="search"
      @click="$emit('updateSearch',item)"
    >
      <template #title>
        <span v-html="highLight(item)"></span>
      </template>
    </van-cell>
  </div>
</template>

<script>
/*
  目标1: 当输入框输入内容时, 请求加载联想建议的数据
  1. 通过监听器watch来监听搜索框中的内容 - 父传子
  2. 当触发监听器时,将修改后的搜索框内容进行接口调用并查询出新的数据列表
  3. 将返回的数据渲染到页面上

  问题1: 当输入一个后台不能查询到结果的查询字符串时, 会出现两种不同的结果 1:[null] 2:[]
  解决1: 如果查询结果为以上两只形式时, 让搜索框的内容为查询列表的第一个元素

  问题2: 在使用该联想功能的过程中发现，无论是删除字符串内容或者是输入字符串内容，只要输入框中有变化就会立马进行接口的访问，带来的问题是当需要删除所有文本并重新输入新文本时，会引发非常多的不必要的请求操作
  解决方案2： 能否在某次输入的一定时间内不去做接口的请求 - 防抖 （在一定时间内如果重复触发某个事件，将会重置该时间，知道最后一次触发事件后才会执行）
  1. lodash类库提供了防抖的方案
    _.debounce(function () { 需要进行防抖操作的逻辑代码 }, 防抖的延时时间)
  2. 使用步骤
    1. import { debounce } from 'lodash'
    2. 找到需要进行防抖的方法，将原方法写在debounce方法的第一个参数中：如handler: debounce(function () {}, 200)
    3. 注意，debounce中的回调函数必须是普通函数，不可以为箭头函数，因为箭头函数没有函数作用域，会影响this指向
*/

/*
  目标2: 联想建议列表中的每一个选项都需要用富文本的形式进行高亮显示
  1. 通过v-html指令实现高亮
  2. ABCDACBCD 将里面的A全部变成<span style="color: red">A</span>
    2.1 replace 去替换字符串中的A (replaceAll替换全部A; replace(/A/gi)正则表达式匹配去全部A)
    2.2 indexOf, findIndex 获取索引去替换
    2.3 split 将符合查询要求的A, 变成数组中元素分割的逗号, 然后用join将逗号转化为<span>
*/

/*
  目标3: 当选中联想建议中的选项时,会将搜索框中的结果改为联想选项内容并进行搜索结果的跳转
  1. 把这个任务交给父组件, 让父组件去做两件事
    1.1 更新搜索框内容
    1.2 开启搜索结果页面
*/
import { getSearchSuggestionsAPI } from '../../../api/index.js'
import { debounce } from 'lodash'
export default {
  name: 'SearchSuggestion',
  props: {
    searchInput: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      suggestion: [] // 联想数据列表
    }
  },
  watch: {
    // 用基本写法时出现问题: 当输入第一个字符时, 并没有监听到结果
    // 'searchInput' (newValue) {
    //   console.log(newValue)
    // }
    // 通过深度监听的完整写法, 解决问题
    searchInput: {
      immediate: true, // 首次监听触发
      // 防抖操作的第一个参数必须是普通函数类型, 不可以是箭头函数(没有this)
      handler: debounce(function (newValue) {
        // 调用查询建议方法
        // console.log('this', this)
        this.loadSearchSuggestions(newValue)
      }, 500)
      // handler: debounce(newValue => {
      //   // 调用查询建议方法
      //   console.log('this', this)
      //   this.loadSearchSuggestions(newValue)
      // }, 2000)
    }
  },
  methods: {
    // 查询建议数据接口
    async loadSearchSuggestions (newValue) {
      try {
        const res = await getSearchSuggestionsAPI(newValue)
        console.log(res)
        // 有时候后端会返回一个[null] [], 可以主动将这两种情况改为searchInput的值作为第一个元素
        if (res.data.data.options.length === 0 || res.data.data.options[0] === null) {
          res.data.data.options[0] = this.searchInput
        }
        this.suggestion = res.data.data.options
        // 富文本高亮 - 仅改变页面, 不改变数据
        // this.suggestion = res.data.data.options.map(item => {
        //   return item.replace(newValue, `<span style="color: red">${newValue}</span>`)
        // })
        // this.suggestion = res.data.data.options.map(item => {
        //   item = item.split(newValue)
        //   return item.join(`<span style="color: red">${newValue}</span>`)
        // })
      } catch (error) {
        console.log(error)
        this.$toast('查询列表失败')
      }
    },

    // 高亮展示数据处理方法
    highLight (value) {
      // value表示需要进行高亮处理的字符串
      // 1. 生成富文本格式 - 搜索框关键字标签形式
      const str = `<span style="color: red;">${this.searchInput}</span>`
      // 2. 通过替换的方式改写字符串
      // 2.1 使用replaceAll
      // const tempStr = value.replaceAll(this.searchInput, str)

      // 2.2 使用正则表达式来实现
      // const reg = new RegExp(this.searchInput, 'gi')
      // const tempStr = value.replace(reg, str)

      // 2.3 通过split和join组合使用
      const tempStr = value.split(this.searchInput).join(str)
      return tempStr
    }
  }
}
</script>

<style scoped lang="less"></style>
